package org.luckyjourney.service.booking.impl;

import cn.hutool.core.util.ObjectUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import org.luckyjourney.controller.wx.WechatPayConfig;
import org.luckyjourney.entity.booking.Orders;
import org.luckyjourney.entity.booking.Refunds;
import org.luckyjourney.entity.booking.dto.OrdersPaymentDTO;
import org.luckyjourney.entity.booking.vo.OrderVO;
import org.luckyjourney.entity.booking.vo.RefundsVO;
import org.luckyjourney.entity.user.User;
import org.luckyjourney.exception.BaseException;
import org.luckyjourney.mapper.booking.OrdersMapper;
import org.luckyjourney.mapper.user.UserMapper;
import org.luckyjourney.service.booking.OrdersService;
import org.luckyjourney.service.booking.WechatPayService;
import org.luckyjourney.util.BaseContext;
import org.luckyjourney.util.WxPayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;

@Service
public class WechatPayServiceImpl implements WechatPayService {
    public static JsapiServiceExtension jsapiServiceExtension;
    public static RefundService refundService;
    private final WechatPayConfig wechatPayConfig;
    @Autowired
    UserMapper userMapper;
    @Autowired
    OrdersService ordersService;

    @Autowired
    OrdersMapper ordersMapper;

    public static final String CNY = "CNY";

    public WechatPayServiceImpl(WechatPayConfig wechatPayConfig) throws Exception {
        this.wechatPayConfig = wechatPayConfig;
        this.init();
    }

    @PostConstruct
    public void init() throws Exception {
        String privateKey = WxPayUtil.loadKeyByResource("wechatPay/apiclient_key.pem");
        // 初始化商户配置
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(wechatPayConfig.getMchId())
                        .privateKey(privateKey)
                        .merchantSerialNumber(wechatPayConfig.getSerialNo())
                        .apiV3Key(wechatPayConfig.getApiV3Key())
                        .build();
        // 初始化服务
        jsapiServiceExtension =
                new JsapiServiceExtension.Builder()
                        .config(config)
                        .signType("RSA") // 不填默认为RSA
                        .build();
        refundService = new RefundService.Builder().config(config).build();
    }

    /**
     * JSAPI支付下单，并返回JSAPI调起支付数据
     * <p>
     * //     * @param details    订单描述
     * //     * @param outTradeNo id
     * //     * @param money      金额
     * //     * @param openId     用户openid
     * //     * @param orderBean  购买商品 goods、充值 charge+
     *
     * @return PrepayWithRequestPaymentResponse 支付信息
     */
    public PrepayWithRequestPaymentResponse prepayWithRequestPayment(OrdersPaymentDTO ordersPaymentDTO) {
        PrepayRequest request = new PrepayRequest();
        //获取订单号
        String ordersNumber = ordersPaymentDTO.getOrdersNumber();
        //获得当前登录人id
        Long currentId = BaseContext.getCurrentId();
        User user = userMapper.selectById(currentId);
        Orders orders = ordersMapper.selectOrdersNumber(ordersNumber);
        if (ObjectUtil.isEmpty(orders)) {
            throw new BaseException("没有该订单信息");
        }
        BigDecimal price = orders.getPrice();
        Amount amount = new Amount();
        System.out.println("price = " + price);
        Integer total = price.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue();
        //支付金额
        amount.setTotal(total);
        amount.setCurrency(CNY);
        // 设置支付成功后的回调
        request.setNotifyUrl(wechatPayConfig.getNotifyUrl());
        request.setAmount(amount);
        //支付项目的名称
        request.setAttach("心理咨询");
        request.setAppid("wx81fa3d1f385a7dda");
        request.setMchid("1644970304");
        //自定义设置支付成功后的商户单号32位字符
        request.setOutTradeNo(ordersNumber);
        //订单描述
        request.setDescription("心理咨询订单");
        Payer payer = new Payer();
        //前端传递的openId
        payer.setOpenid(user.getOpenid());
        request.setPayer(payer);
        // 使用微信支付sdk调用接口
        PrepayWithRequestPaymentResponse response = jsapiServiceExtension.prepayWithRequestPayment(request);
        return response;
    }

    @Override
    public Transaction queryOrderById(String ordersNumber) {
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wechatPayConfig.getMchId());
        queryRequest.setOutTradeNo(ordersNumber);
        //查询订单是否支付
        Transaction transaction = jsapiServiceExtension.queryOrderByOutTradeNo(queryRequest);
        System.out.println("transaction = " + transaction);
        return transaction;
    }

    /**
     * 申请退款
     *
     * @param ordersPaymentDTO
     * @return
     */
    @Override
    public Refund prepayWithRefundRequests(OrdersPaymentDTO ordersPaymentDTO) {
        //订单号
        String ordersNumber = ordersPaymentDTO.getOrdersNumber();
        CreateRequest createRequest = new CreateRequest();
        createRequest.setOutTradeNo(ordersNumber);
        SimpleDateFormat yyyyMMddHHmmssSSS = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String format = yyyyMMddHHmmssSSS.format(new Date());
        String refundOrdersNumber = "TK" + format;
        createRequest.setOutRefundNo(refundOrdersNumber);
        Orders orders = ordersMapper.selectOrdersNumber(ordersNumber);
        AmountReq amountReq = new AmountReq();
        BigDecimal price = orders.getPrice();
        System.out.println("price = " + price);
        Integer total = price.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue();
        System.out.println("total = " + total);
        //支付金额
        amountReq.setTotal(Long.valueOf(total));
        amountReq.setRefund(Long.valueOf(total));
        amountReq.setCurrency(CNY);
        createRequest.setAmount(amountReq);
        //更新退款订单号
        Orders orders1 = new Orders();
        orders1.setRefundOrdersNumber(refundOrdersNumber);
        orders1.setId(orders.getId());
        //修改为已退款
        orders1.setStatus(Orders.CONFIRMED);
        orders1.setRefundTime(LocalDateTime.now());
        ordersMapper.update(orders1);
        return refundService.create(createRequest);
    }

    /**
     * 查询单笔退款的金额
     *
     * @param refundOrdersNumber
     * @return
     */
    @Override
    public Refund refundSuccess(String refundOrdersNumber) {
        QueryByOutRefundNoRequest query = new QueryByOutRefundNoRequest();
        query.setOutRefundNo(refundOrdersNumber);
        return refundService.queryByOutRefundNo(query);
    }

    /**
     * 申请退款
     *
     * @param ordersPaymentDTO
     * @return
     */
    @Override
    public Boolean RequesRefund(OrdersPaymentDTO ordersPaymentDTO) {
        String ordersNumber = ordersPaymentDTO.getOrdersNumber();
        if (ObjectUtil.isEmpty(ordersNumber)) {
            throw new BaseException("请选择要退款的订单");
        }
        Orders orders = ordersMapper.selectOrdersNumber(ordersNumber);
        Long id = orders.getId();
        Long currentId = BaseContext.getCurrentId();
        if (orders.getStatus().equals(Orders.CONFIRMED)) {
            throw new BaseException("该订单已经退款请在余额中查看");
        }
        if (orders.getStatus().equals(Orders.REFUND_REQUESTS)) {
            throw new BaseException("该订单已经申请退款，无需重复申请，请等待审核");
        }
        Refunds refund = new Refunds();
        refund.setApplicationId(currentId);
        refund.setOrdersNumber(ordersNumber);
        int Refunds = ordersMapper.delectRefunds(refund);
        if (Refunds > 0) {
            Refunds refunds = new Refunds();
            refunds.setApplicationId(currentId);
            refunds.setOrdersId(id);
            refunds.setOrdersNumber(ordersNumber);
            refunds.setUserId(orders.getUserId());
            refunds.setRefundStatus(1);
            refunds.setApplicationTime(LocalDateTime.now());
            refunds.setRequestDescription(ordersPaymentDTO.getRequestDescription());
            int i = ordersMapper.insertRefunds(refunds);
            if (i > 0) {
                // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
                Orders orders1 = Orders.builder()
                        .id(id)
                        .status(Orders.REFUND_REQUESTS)
                        .requestDescription(ordersPaymentDTO.getRequestDescription())
                        .applicationTime(LocalDateTime.now())
                        .build();
                ordersMapper.update(orders1);


                return true;
            }
        }
        return false;
    }

    /**
     * 退款详细
     *
     * @param ordersPaymentDTO
     * @return
     */
    @Override
    public RefundsVO refunddetails(OrdersPaymentDTO ordersPaymentDTO) {
        Long id = ordersPaymentDTO.getId();
        String ordersNumber = ordersPaymentDTO.getOrdersNumber();
        if (ObjectUtil.isEmpty(id)) {
            throw new BaseException("该订单不存在");
        }
        //根据当前申请人进行查询详情
        Refunds refunds = new Refunds();
        refunds.setId(id);
        refunds.setOrdersNumber(ordersNumber);
        Long currentId = BaseContext.getCurrentId();
        refunds.setApplicationId(currentId);
        RefundsVO refundsVO = ordersMapper.selectRefunddetails(refunds);
        if (ObjectUtil.isEmpty(refundsVO)) {
            throw new BaseException("该订单你未申请退款");
        }
        Long ordersId = refundsVO.getOrdersId();
        OrderVO orderVO = ordersMapper.select(ordersId);
        LocalDateTime paymentTime = orderVO.getPaymentTime();
        refundsVO.setPaymentTime(paymentTime);
        Integer status = orderVO.getStatus();
        BigDecimal price = orderVO.getPrice();
        LocalDateTime createTime = orderVO.getCreateTime();
        refundsVO.setCreateTime(createTime);
        refundsVO.setPrice(price);
        refundsVO.setStatus(status);
        return refundsVO;
    }

    /**
     * 取消退款申请
     *
     * @param ordersPaymentDTO
     * @return
     */
    @Override
    public Boolean cancelRefund(OrdersPaymentDTO ordersPaymentDTO) {
        Long id = ordersPaymentDTO.getId();
        if (ObjectUtil.isEmpty(id)) {
            throw new BaseException("请选择要取消的订单");
        }
        //取消退款申请修改状态
        Refunds refunds = new Refunds();
        refunds.setRefundStatus(4);
        refunds.setOrdersId(id);
        Boolean aBoolean = ordersMapper.updateRefund(refunds);
        if (aBoolean == true) {
            // 取消申请时候把订单修改为已支付
            Orders orders1 = Orders.builder()
                    .id(id)
                    .status(Orders.TO_BE_CONFIRMED)
                    .build();
            ordersMapper.update(orders1);
        }
        return aBoolean;
    }
}
